package cn.netuo.bumbersoll.mqtt;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Binder;
import android.os.IBinder;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.UUID;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import cn.netuo.bumbersoll.App;
import cn.netuo.bumbersoll.BizConstant;
import cn.netuo.bumbersoll.R;
import cn.netuo.bumbersoll.helper.MqttFromCHelper;
import lib.grasp.util.L;

public class MQTTService extends Service {

    /** 客户端 */
    private static  MqttAndroidClient       mClient;
    /** 连接器 */
    private         MqttConnectOptions      mConnOption;
    /** 消息回调器 */
    private         IGetMessageCallBack     mMsgListener;

    @Override
    public IBinder onBind(Intent intent) {
        L.logOnly(getClass().getName() + "onBind");
        return new CustomBinder();
    }

    /** IBinder代理类, 主要向外暴露Service, 获取Service本身 */
    public class CustomBinder extends Binder {
        public MQTTService getService(){
            return MQTTService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }

    /** 初始化连接参数 */
    private void init() {
        // 服务器地址（协议+地址+端口号）
        String uri = BizConstant.MQTT_HOST;
        mClient = new MqttAndroidClient(this, uri, UUID.randomUUID().toString());

        mClient.setCallback(mMqttCallback);                                 // 设置MQTT监听并且接受消息

        mConnOption = new MqttConnectOptions();
        mConnOption.setCleanSession(false);                                 // 清除缓存
        mConnOption.setConnectionTimeout(10);                               // 设置超时时间，单位：秒
        mConnOption.setKeepAliveInterval(35 * 60);                           // 心跳时间，单位为秒。即要求broker多长时间确认一次Client端是否在线(mqtt-client本身不发送心跳包, 只是broker会按该时间间隔定期检查client, 看规定的时间内是否有通讯, 有则活,无则认为断开)
        mConnOption.setUserName(BizConstant.MQTT_UNAME);                    // 用户名
        mConnOption.setPassword(BizConstant.MQTT_PWD.toCharArray());        // 密码,将字符串转换为字符串数组
        mConnOption.setAutomaticReconnect(true);                            // 重连
//        mConnOption.setSocketFactory(getSocketFactory());

        // 最后的遗嘱(last will message)
        // MQTT本身就是为信号不稳定的网络设计的，所以难免一些客户端会无故的和Broker断开连接。
        // 当客户端连接到Broker时，可以指定LWT，Broker会定期检测客户端是否有异常。
        // 当客户端异常掉线时，Broker就往连接时指定的topic里推送当时指定的LWT消息。
        boolean doConnect = true;
        String message  = MqttFromCHelper.getLastWill(this);
        String topic    = BizConstant.MQTT_SENDTOPIC;
        try {
            mConnOption.setWill(topic, message.getBytes(), 0, false);
        } catch (Exception e) {
            doConnect = false;
            iMqttActionListener.onFailure(null, e);
        }
        if (doConnect) doClientConnection();
    }

    private SocketFactory getSocketFactory() {
        try {
            SSLContext context;
            KeyStore ts = KeyStore.getInstance("BKS");
            ts.load(getResources().openRawResource(R.raw.mqtt_server), "rooten".toCharArray());
//            ts.load((KeyStore.LoadStoreParameter)getResources().openRawResource(R.raw.mqtt_server));
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
            tmf.init(ts);
            TrustManager[] tm = tmf.getTrustManagers();
            context = SSLContext.getInstance("TLS");
//            context = SSLContext.getInstance("TLS","AndroidOpenSSL");
            context.init(null, tm, null);

            return context.getSocketFactory();
        } catch (Exception e) {
            return null;
        }
    }

    private SocketFactory getSocketFactory1() {
        try {
            // 取到证书的输入流
            InputStream is = new FileInputStream("/sdcard/ca.crt");
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate ca = cf.generateCertificate(is);

            // 创建 Keystore 包含我们的证书
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null);
            keyStore.setCertificateEntry("anchor", ca);

            // 创建一个 TrustManager 仅把 Keystore 中的证书 作为信任的锚点
            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            // 用 TrustManager 初始化一个 SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLSv1","AndroidOpenSSL");
            sslContext.init(null, trustManagers, null);
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            return null;
        }
    }

    /** 连接MQTT服务器 */
    public void doClientConnection() {
        if (!mClient.isConnected() && isConnectIsNormal()) {
            try {
                mClient.connect(mConnOption, this, iMqttActionListener);
            } catch (MqttException e) {
                L.logOnly("-doClientConnection:" + e.getMessage());
            }
        }
    }

    /** 连接动作监听 */
    private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken arg0) {
            L.logOnly("MQTT连接成功, 订阅主题:" + BizConstant.ARG_MQTT_TOPIC);
            if (mMsgListener != null) mMsgListener.onConnStateChanged(true);
            try {
                mClient.subscribe(BizConstant.ARG_MQTT_TOPIC, 1);   // 订阅myTopic话题
            } catch (
                    Exception e) {
                L.logOnly("-iMqttActionListener-onSuccess:" + e.getMessage());
            }
        }

        @Override
        public void onFailure(IMqttToken arg0, Throwable arg1) {
            L.logOnly("-iMqttActionListener-onFailure:" + arg1);
            if (mMsgListener != null) mMsgListener.onConnStateChanged(false);
        }
    };

    /** 消息监听 */
    private MqttCallbackExtended mMqttCallback = new MqttCallbackExtended() {

        @Override
        public void connectComplete(boolean reconnect, String serverURI) {
            L.logOnly("--MQTT重连成功");
            if (mMsgListener != null) mMsgListener.onConnStateChanged(true);
//            MqttFromCHelper.sendHeartBeat(MQTTService.this);
            App.getApp().getLocalBroadMgr().broadAction(BizConstant.BROAD_HEARTBEAT);
        }

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
            String str1 = new String(message.getPayload());
            L.logOnly("--收到消息---messageArrived:" + str1);
            if (mMsgListener != null) mMsgListener.onNewMessage(str1);
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken arg0) {
            L.logOnly("--消息/心跳发送完成---deliveryComplete");
        }

        @Override
        public void connectionLost(Throwable arg0) {
            L.logOnly("--失去连接---connectionLost");
            if (mMsgListener != null) mMsgListener.onConnStateChanged(false);
        }
    };

    /** 发送消息 */
    public static void publish(String msg){
        String topic = BizConstant.MQTT_SENDTOPIC;
        Integer qos = 0;
        Boolean retained = false;
        try {
            if (mClient != null && mClient.isConnected()){
                mClient.publish(topic, msg.getBytes(), qos.intValue(), retained.booleanValue());
            }
        } catch (MqttException e) {
            L.logOnly(e.getMessage());
        }
    }

    @Override
    public void onDestroy() {
        stopSelf();
        try {
            if(mClient != null) {
                mClient.disconnect();
                mClient.unregisterResources();
            }
//            if(mClient != null && mClient.isConnected()) mClient.disconnect();
        } catch (Exception e) {
            L.logOnly("-onDestroy:" + e.getMessage());
        }
        super.onDestroy();
    }


    /** 判断网络是否连接 */
    private boolean isConnectIsNormal() {
        ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connectivityManager.getActiveNetworkInfo();
        if (info != null && info.isAvailable()) {
            String name = info.getTypeName();
            L.logOnly("MQTT当前网络名称：" + name);
            return true;
        } else {
            L.logOnly("MQTT 没有可用网络");
            return false;
        }
    }

    /** 设备MQTT消息接收回调器 */
    public void setIGetMessageCallBack(IGetMessageCallBack mMsgListener){
        this.mMsgListener = mMsgListener;
    }

}